package com.purdue.edu.psychotron.shared;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * A vertical panel. You can add Widgets with labels. Widgets will be
 * collapsible by clicking on a label. You can register a Listener that would be
 * notified of any widgets expanding and collapsing.
 */
public class SideBar extends VerticalPanel {
  private class HeaderWidget extends Label {
    private ClickListener clickListener = new ClickListener() {
      public void onClick(Widget w) {
        if (null != managedWidget) {
          boolean expanded = !managedWidget.isVisible();
          if (notifyListeners(managedWidget, expanded))
            setExpanded(managedWidget, expanded);
        }
      }
    };

    private Widget managedWidget;

    public HeaderWidget(Widget managed, String txt, boolean expanded) {
      super(txt);
      managedWidget = managed;

      addStyleName("mvz-Sidebar-HeaderWidget");
      setState(expanded);
      addClickListener(clickListener);
    }

    public void setState(boolean expanded) {
      if (expanded) {
        removeStyleName("closed");
        addStyleName("opened");
        setTitle("Click to close");
      } else {
        removeStyleName("opened");
        addStyleName("closed");
        setTitle("Click to expand");
      }
    }
  }

  public interface Listener {
    public boolean onWidgetClosing(Widget w);

    public boolean onWidgetOpening(Widget w);
  }

  private ArrayList<Listener> listeners = new ArrayList<Listener>();

  private HashMap<Widget,Widget> widgetToHeaderMap = new HashMap<Widget,Widget>();

  public SideBar() {
    super();
    addStyleName("mvz-Sidebar");
  }

  public void add(Widget w, String label, boolean expanded) {
    w.setVisible(expanded);
    add(w, new HeaderWidget(w, label, expanded));
  }

  public void add(Widget w, Widget headerWidget) {
    w.addStyleName("mvz-Sidebar-Widget");
    widgetToHeaderMap.put(w, headerWidget);
    add(headerWidget);
    add(w);
  }

  public void addListener(Listener l) {
    listeners.add(l);
  }

  private boolean notifyListeners(Widget w, boolean expanded) {
    boolean allow = true;
    if (expanded) {
      for (Iterator<Listener> i = listeners.iterator(); i.hasNext();) {
        allow = allow && i.next().onWidgetOpening(w);
      }
    } else {
      for (Iterator<Listener> i = listeners.iterator(); i.hasNext();) {
        allow = allow && i.next().onWidgetClosing(w);
      }
    }
    return allow;
  }

  public boolean remove(Widget w) {
    if (widgetToHeaderMap.keySet().contains(w)) {
      Widget header = widgetToHeaderMap.get(w);
      remove(header);
    }
    return remove(w);
  }

  public void removeListener(Listener l) {
    listeners.remove(l);
  }

  public void setExpanded(Widget w, boolean expanded) {
    if (!widgetToHeaderMap.containsKey(w))
      return;

    w.setVisible(expanded);
    Widget header = widgetToHeaderMap.get(w);
    if (header instanceof HeaderWidget) {
      HeaderWidget headerWidget = (HeaderWidget) header;
      headerWidget.setState(expanded);
    }
  }
  
  public void showOnly(Widget thisOne) {
    for (Iterator<Widget> i = widgetToHeaderMap.keySet().iterator(); i.hasNext(); ) {
      Widget w = i.next();
      setExpanded(w, (thisOne == w));
    }
  }
}